package com.xncoding.async.future;

import java.util.Random;
import java.util.concurrent.*;

import static java.lang.Thread.sleep;

public class SquareCalculator {
//    private ExecutorService executor = Executors.newSingleThreadExecutor();
    private ExecutorService executor = Executors.newFixedThreadPool(2);
    public Future<Integer> calculate(Integer input) {
        return executor.submit(() -> {
            System.out.printf("计算%d的平方%n", input);
            sleep(1000);
            return input * input;
        });
    }
    /**
     * Future.isDone()告诉我们执行器是否已经完成任务处理。如果任务完成，它将返回true；否则，返回false
     */
    public void calculate00() throws InterruptedException, ExecutionException, TimeoutException {
        Future<Integer> future = new SquareCalculator().calculate(10);

        while(!future.isDone()) {
            System.out.println("计算中...");
            sleep(300);
        }

        Integer result = future.get();
        System.out.println(result);
         result = future.get(500, TimeUnit.MILLISECONDS);
        System.out.println(result);
    }

    /**
     * 终端底层线程
     */
    public void calculate01() throws InterruptedException, ExecutionException, TimeoutException {
        Future<Integer> future = new SquareCalculator().calculate(4);

        boolean canceled = future.cancel(true);
        boolean canceled0 = future.isCancelled();
    }
    public void calculate02() throws InterruptedException, ExecutionException, TimeoutException {
        SquareCalculator squareCalculator = new SquareCalculator();

        Future<Integer> future1 = squareCalculator.calculate(10);
        Future<Integer> future2 = squareCalculator.calculate(100);

        while (!(future1.isDone() && future2.isDone())) {
            System.out.printf(
                    "future1 is %s and future2 is %s%n",
                    future1.isDone() ? "done" : "not done",
                    future2.isDone() ? "done" : "not done"
            );
            sleep(300);
        }

        Integer result1 = future1.get();
        Integer result2 = future2.get();

        System.out.println(result1 + " and " + result2);

        squareCalculator.shutdown();
    }

    private void shutdown() {
    }








    private static class Task implements Callable<String> {

        private int sleep ;
        public Task(int sleep) {
            this.sleep = sleep ;
        }

        @Override
        public String call() throws Exception {
            TimeUnit.SECONDS.sleep(this.sleep) ;
            return "success";
        }

    }
    public  void  testTask00() throws ExecutionException, InterruptedException {
        ThreadPoolExecutor executor = new ThreadPoolExecutor(3, 3, 60, TimeUnit.SECONDS, new ArrayBlockingQueue<>(10)) ;
        Future<String> future1 = executor.submit(new Task(3)) ;
        Future<String> future2 = executor.submit(new Task(2)) ;
        Future<String> future3 = executor.submit(new Task(1)) ;
        String result1 = future1.get() ;
        String result2 = future2.get() ;
        String result3 = future3.get() ;
        System.out.println("result1：" + result1 + "\t" + "result2：" + result2 + "\t" + "result3：" + result3) ;

    }

    private static class Task01 implements Callable<String> {
        private int time;
        private String name ;
        public Task01(int time, String name) {
            this.time = time ;
            this.name = name ;
        }
        @Override
        public String call() throws Exception {
            TimeUnit.SECONDS.sleep(this.time) ;
            return name ;
        }

    }
    public  void  testTask01() throws ExecutionException, InterruptedException {
        ThreadPoolExecutor executor = new ThreadPoolExecutor(3, 3, 60, TimeUnit.SECONDS, new ArrayBlockingQueue<>(10)) ;
        CompletionService<String> cs = new ExecutorCompletionService<>(executor) ;
        cs.submit(new Task01(3, "name" + 3)) ;
        cs.submit(new Task01(1, "name" + 1)) ;
        cs.submit(new Task01(2, "name" + 2)) ;
        for (int i = 0; i < 3; i++) {
            System.out.println(cs.take().get()) ;
        }
    }

    /**
     * 简单异步任务链式调用执行
     */
    public void  testAsync(){

        ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 5, 60, TimeUnit.SECONDS, new ArrayBlockingQueue<>(10)) ;
        CompletableFuture.runAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(3) ;
                System.out.println(Thread.currentThread().getName() + ", 1 任务执行完成") ;
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, executor).thenRun(() -> {
            try {
                TimeUnit.SECONDS.sleep(2) ;
                System.out.println(Thread.currentThread().getName() + ", 2 任务执行完成") ;
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }) ;
        System.out.println("主线程：" + Thread.currentThread().getName()) ;
        executor.shutdown() ;
    }

    /**
     * 获取上一步任务执行结果及任务完成处理
     */
    public void  testAsync00(){
        CompletableFuture.supplyAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(3) ;
                System.out.println(Thread.currentThread().getName() + ", 1 任务执行完成") ;
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "1" ;
        }, executor).thenApply(res -> {
            System.out.println("获取到上一步任务执行结果：" + res) ;
            try {
                TimeUnit.SECONDS.sleep(2) ;
                System.out.println(Thread.currentThread().getName() + ", 2 任务执行完成") ;
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "2" ;
        }).whenComplete((res, tx) -> {
            System.out.println("获取到结果：" + res) ;
            if (tx != null) {
                System.err.println("发生错误了：" + tx.getMessage()) ;
            }
            executor.shutdown();
        }) ;
        System.out.println("主线程：" + Thread.currentThread().getName()) ;
    }

    /**
     * 异步任务异常处理
     */
    public void  testAsync01(){

        CompletableFuture.supplyAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(3) ;
                System.out.println(Thread.currentThread().getName() + ", 1 任务执行完成") ;
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "1" ;
        }, executor).thenApply(res -> {
            System.out.println("获取到上一步任务执行结果：" + res) ;
            try {
                TimeUnit.SECONDS.sleep(2) ;
                System.out.println(Thread.currentThread().getName() + ", 2 任务执行完成") ;
                System.out.println(1 / 0) ;
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "2" ;
        }).exceptionally(tx -> {
            System.out.println(Thread.currentThread().getName() + ", 任务执行发生了异常") ;
            return "error" ;
        }).whenComplete((res, tx) -> {
            System.out.println("获取到结果：" + res) ;
            if (tx != null) {
                System.err.println("发生错误了：" + tx.getMessage()) ;
            }
            executor.shutdown();
        }) ;
        System.out.println("主线程：" + Thread.currentThread().getName()) ;
    }

    /**
     * 所有任务完成才算完成任务
     * CompletableFuture.allOf
     */
    public void  testAsync02(){

        CompletableFuture<Double> calc1 = CompletableFuture.supplyAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(2) ;
                System.out.println(Thread.currentThread().getName() + ", calc1任务执行完成") ;
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return 10D ;
        }, executor) ;

        CompletableFuture<Double> calc2 = CompletableFuture.supplyAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(5) ;
                System.out.println(Thread.currentThread().getName() + ", calc2任务执行完成") ;
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return 20D ;
        }, executor) ;
// 当任何一个任务发生异常，这里的tx都不会为null
        CompletableFuture.allOf(calc1, calc2).whenComplete((res, tx) -> {
            System.out.println("获取到结果：" + res + ", " + tx) ;
            try {
                System.out.println(calc1.get()) ;
                System.out.println(calc2.get()) ;
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
            executor.shutdown();
        }) ;

    }

    /**
     * 异步任务谁快谁就进入下一步的执行
     */
    public void  testAsync03(){
        CompletableFuture<Double> task1 = CompletableFuture.supplyAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(2) ;
                System.out.println(Thread.currentThread().getName() + ", 任务1执行完成") ;
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return 10d ;
        }, executor) ;
        CompletableFuture<Double> task2 = CompletableFuture.supplyAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(2) ;
                System.out.println(Thread.currentThread().getName() + ", 任务2执行完成") ;
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return 20d ;
        }, executor) ;
        task1.applyToEither(task2, res -> {
            return res ;
        }).whenComplete((res, tx) -> {
            System.out.println("获取到结果：" + res) ;
            if (tx != null) {
                System.err.println("发生错误了：" + tx.getMessage()) ;
            }
            executor.shutdown();
        }) ;
    }

    /**
     * 两个异步任务都执行完了才继续执行
     * CompletableFuture.runAfterBoth
     */
    public void  testAsync04(){
        CompletableFuture<Double> task1 = CompletableFuture.supplyAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(2) ;
                System.out.println(Thread.currentThread().getName() + ", 任务1执行完成") ;
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return 10d ;
        }, executor) ;
        CompletableFuture<Double> task2 = CompletableFuture.supplyAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(2) ;
                System.out.println(Thread.currentThread().getName() + ", 任务2执行完成") ;
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return 20d ;
        }, executor) ;
        task1.runAfterBoth(task2, () -> {
            System.out.println("任务都执行完成了...") ;
        }).whenComplete((res, tx) -> {
            System.out.println("获取到结果：" + res) ;
            if (tx != null) {
                System.err.println("发生错误了：" + tx.getMessage()) ;
            }
            executor.shutdown();
        }) ;
    }

    /**
     * 任意一个任务执行完成就算完成
     * CompletableFuture.anyOf
     */
    public void  testAsync05(){

        CompletableFuture<String> task1 = CompletableFuture.supplyAsync(() -> {
            try {
                sleep(1000) ;
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println("我是任务1") ;
            return "Task1" ;
        }, executor) ;

        CompletableFuture<String> task2 = CompletableFuture.supplyAsync(() -> {
            try {
                sleep(3000) ;
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println("我是任务2") ;
            System.out.println(1 / 0) ;
            return "Task2" ;
        }, executor) ;
// 任意一个任务执行完成就算完成
// 当任务执行发生异常后，th才不会为null
        CompletableFuture.anyOf(task1, task2).whenCompleteAsync((v, th) -> {
            System.out.println("v = " + v) ;
            System.out.println("th = " + th) ;
        }, executor) ;
    }

    /**
     * 接收上一个任务的执行结果
     */
    public void  testAsync06(){
        CompletableFuture.supplyAsync(() -> {
            try {
                sleep(2000) ;
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println("第一个任务执行完成...") ;
            // System.out.println(1 / 0) ;
            return new Random().nextInt(10000) ;
        }, executor).thenAcceptAsync(res -> { // 接收上一个任务的执行结果
            System.out.println("任务执行结果：" + res) ;
        }, executor) ;
    }

}
